import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;


public class RSADemo {

    public static BASE64Decoder Base64Decode;
    public static BASE64Encoder Base64Encode;

    // 公钥
    public static String str_pubK = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDE9LhxI1CvTYCSIxQr8JqV/7Qk" +
            "Wc48uVDCpmJeHmL0ICIybM5zDN/f7VEcaA0G1peZ/8klX6fnPtH5ItRSnXPbCiwu" +
            "Q5+wPTMLLd5J8d0zhtiTGwMcbCWFgN+7lKfQy8B6fVIMybpi7leqhT4+iwjzG8xw" +
            "maX8qmsMtyUFtuxyZQIDAQAB";

    // 私钥
    public static String str_priK = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMT0uHEjUK9NgJIj" +
            "FCvwmpX/tCRZzjy5UMKmYl4eYvQgIjJsznMM39/tURxoDQbWl5n/ySVfp+c+0fki" +
            "1FKdc9sKLC5Dn7A9Mwst3knx3TOG2JMbAxxsJYWA37uUp9DLwHp9UgzJumLuV6qF" +
            "Pj6LCPMbzHCZpfyqawy3JQW27HJlAgMBAAECgYB4M5aBTflHE7i893WvH2do1ibd" +
            "7IUmoD6+nQb5w/fGX/oe5jLVGm1jX5WaDZKtsrfRP79F9OwnADrrnqsQRJHYcQbP" +
            "S7VYL7NgvBy+LkfzuVIVLBGxt3QCoWIj9JooXvniDLDKw5Sy7FGfrLpJsfyTFqDb" +
            "4EI9X0XeDlldn9+M/QJBAO2Wi/dPFixp27dg1bFx6QXoBhpJCuhhRNP1aBHf7nhx" +
            "1mbEkeoNu0Mgacc3VJuRZyHiQDyaTMUSngd33134mOcCQQDUOBUekQecB/cFMS1+" +
            "gmJJPnEE2yJ5nF1DjVZ+wRFXrVX9/ronI6SfP/Uk23vdVs7PCc96iCwh340BAStH" +
            "3LTTAkBVVqHnruyT/2IAODQJjJTankCy6FGWrnl+eMNsyDZr5NfSCgEvRMdikR3t" +
            "hJ5LUqrsrMvN+M5iaxGANTpyEn05AkBxPC+ArNALoHBc892biESbYlb5yVd+3kEh" +
            "X1QMtEXlq5abvYRkh+86De1nKjnQY5ZcAJcVgX1S4a6iH5aRdKGDAkEA65hyAmmd" +
            "B+iSrFWEz+rPgfPZ1DzICFGrz2EIyrKPDcwOqtbQe5IR+2nZ3BjRX+PuLCvsn9JJ" +
            "EZLob1qi9YvWfw==";

    // 静态代码块，类被加载会优先加载它，并且只加载一次。
    static {
        Base64Decode = new BASE64Decoder();
        Base64Encode = new BASE64Encoder();
    }

    // 公钥
    public static PublicKey getPublicKey(String key) throws Exception {
        // 解码得到真实数据
        byte[] keyBytes = Base64Decode.decodeBuffer(key);
        // 密钥实例化出来一个key
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        // 得到一个RSA单例模型
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    // 私钥
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes = Base64Decode.decodeBuffer(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }


    //
    public static byte[] sign(byte[] data) throws Exception {
        PrivateKey priK = getPrivateKey(str_priK);
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initSign(priK);
        sig.update(data);
        return sig.sign();
    }

    public static boolean verify(byte[] data, byte[] sign) throws Exception {
        PublicKey pubK = getPublicKey(str_pubK);
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initVerify(pubK);
        sig.update(data);
        return sig.verify(sign);
    }

    public static byte[] encrypt(byte[] bt_plaintext) throws Exception {
        PublicKey publicKey = getPublicKey(str_pubK);
        Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding",  "BC");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] bt_encrypted = cipher.doFinal(bt_plaintext);
        return bt_encrypted;
    }

    public static byte[] decrypt(byte[] bt_encrypted) throws Exception {
        PrivateKey privateKey = getPrivateKey(str_priK);
        Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding",  "BC");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] bt_original = cipher.doFinal(bt_encrypted);
        return bt_original;
    }


    public static void main(String[] args) throws Exception{
        String str_plaintext = "lxflxflxflxf";
        byte[] bt_cipher = encrypt(str_plaintext.getBytes());
        System.out.println("明文: " + str_plaintext);
        System.out.println("加密后: " + byteToHexString(bt_cipher));

        byte[] bt_original = decrypt(bt_cipher);
        String str_original = new String(bt_original);
        System.out.println("解密结果: " + str_original);

        System.out.println("===========================");

        String str = "mv sign data";
        byte[] signature = sign(str.getBytes());
        System.out.println("原文: " + str);
        System.out.println("产生签名: " + Base64Encode.encodeBuffer(signature));

        boolean status = verify(str.getBytes(), signature);
        System.out.println("验证情况: " +status);
    }


    public static String byteToHexString(byte[] by) {
        StringBuffer SB = new StringBuffer();
        int i = 0;
        while (i < by.length) {
            int k = by[i];
            int j = k;
            if (k < 0) {
                j = k + 256;
            } if (j < 16) {
                SB.append("0");
            }
            SB.append(Integer.toHexString(j));
            i += 1;
        }
        return SB.toString();
    }
}
